extern ftell
extern fseek
extern malloc
extern free
extern printf
extern fprintf
extern fopen
extern fscanf
extern fclose
extern fwrite
extern lista_agregar
extern lista_crear
extern lista_borrar

;AUXILIARES
global nodo_borrar
global recorrerYBorrar
global nodo_buscar
global nodo_prefijo
global dame_prefijos
global caracteres_de_tecla
global convertir

%define SEEK_SET 0
%define EOF -1


global trie_crear
global nodo_crear
global insertar_nodo_en_nivel
global trie_agregar_palabra
global trie_construir
global trie_borrar
global trie_imprimir
global buscar_palabra
global palabras_con_prefijo
global trie_pesar

; SE RECOMIENDA COMPLETAR LOS DEFINES CON LOS VALORES CORRECTOS
%define offset_sig 0
%define offset_hijos 8
%define offset_c 16
%define offset_fin 17

%define size_nodo 18

%define offset_raiz 0

%define size_trie 8


%define offset_prim 0
%define offset_valor 0
%define offset_sig_lnodo 8


%define NULL 0

%define FALSE 0
%define TRUE 1

section .rodata

section .data

file_mode: db "r",0
scan_mode: db "%s ",0
append_mode: db "a",0
salto: db 10, 0

section .text

;FUNCIONES AUXILIARES.
;void nodo_borrar(nodo *n){

nodo_borrar:

	;stack frame

	push rbp;			;estoy alineado
	mov rbp, rsp

	call free

	pop rbp
	ret

;}

; nodo* nodo_buscar(nodo *n, char c){

nodo_buscar:

	;stack frame
        push rbp
        mov rbp, rsp
	push rbx
        push r12

	mov r12, rdi
	mov bl, sil

.ciclo:

	cmp qword r12, NULL
	je .termina
	cmp byte bl, [r12+offset_c]
	je .termina
	mov r12, [r12+offset_sig]
	jmp .ciclo

.termina:
	mov rax, r12

	pop r12
	pop rbx
	pop rbp
	ret

;}

; char convertir(char a){
convertir:

	push rbp                        
	mov  rbp, rsp
	push r12
	sub rsp, 8

	xor r12, r12
	mov byte r12b, dil 									;r12 =c

	cmp r12, 48
	jl .AsignarA

	cmp r12, 122
	jg .AsignarA

	cmp r12, 57
	jg .Intermedio1
	.FinIntermedio1:

	cmp r12, 90
	jg .Intermedio2
	.FinIntermedio2:

	cmp r12, 65
	jge .Intermedio3

	jmp .Fin
	
	.Intermedio1:
	cmp r12, 65
	jl .AsignarA
	jmp .FinIntermedio1

	.Intermedio2:
	cmp r12, 97
	jl .AsignarA
	jmp .FinIntermedio2

	.Intermedio3:
	cmp r12, 90
	jg .Fin
	add r12, 32
	jmp .Fin

	.AsignarA:
	mov r12, 97
	jmp .Fin

	.Fin:
	mov rax, r12
	
	add rsp, 8
	pop rbp
	pop r12
	ret

;}



; nodo* nodo_prefijo(nodo *n, char *p ){

nodo_prefijo:

	;COMPLETAR AQUI EL CODIGO
        ;stack frame
        push rbp
        mov rbp, rsp
        push rbx
        push r12

        mov rbx, rdi
        mov r12, rsi

.ciclo:

        cmp [r12], byte NULL
        je .termino
        mov rdi, rbx
        mov sil, byte [r12]
        call nodo_buscar
        cmp qword rax, NULL
        je .noLoEncontre
        mov rbx, [rax+offset_hijos]
        add r12, 1
        jmp .ciclo

.termino:

	mov rax, rbx
        pop r12
        pop rbx
        pop rbp
        ret

.noLoEncontre:

	mov rax, NULL
	pop r12
	pop rbx
	pop rbp
	ret


;}

; void recorrerYBorrar(nodo *nodo){

recorrerYBorrar:

	;stack frame
	;no modifico RBX, R13, R14 y R15
	push rbp
        mov rbp, rsp
	push r12

	sub rsp, 8			;estoy alineado

	mov r12, rdi

	cmp qword [r12+offset_sig], NULL
	je .noTieneSiguiente
	mov rdi, [r12+offset_sig]
	call recorrerYBorrar

.noTieneSiguiente:

	cmp qword [r12+offset_hijos], NULL
	je .borrarNodo
	mov rdi, [r12+offset_hijos]
	call recorrerYBorrar

.borrarNodo:

	mov rdi, r12
	call nodo_borrar

	add rsp, 8
	pop r12
	pop rbp
	ret

;}

; void dame_prefijos(nodo *n, char *prefijo, listaP *l){

dame_prefijos:

	;stack frame
        push rbp
        mov rbp, rsp
	push rbx
        push r12
        push r13
        push r14
	push r15

	sub rsp, 8   ; alineo la pila	

	;los paramatros llegan por estos 3 resgistros
	;rdi(*n), rsi(*prefijo), rdx(*l)
	mov rbx, rdi
	mov r12, rsi
	mov r13, rdx

	mov r15, r12

	cmp qword rbx,  NULL
	je .terminar

	xor rdi, rdi

	mov rdi, 1024
	call malloc
	mov r14, rax	;buffer

.cpy: ;copio el prefijo al buffer

	cmp byte [r12], NULL
	je .terminoLaCopia
	mov cl, byte [r12]
	mov byte [rax], cl
	add rax, 1
	add r12, 1
	jmp .cpy

.terminoLaCopia:

	mov cl, byte [rbx+offset_c]
	mov byte [rax], cl
	add rax, 1
	mov [rax], byte NULL  ; extiendo el prefijo para preparlo para la llamada recursiva 


	cmp byte [rbx+offset_fin], TRUE
	je .agregarALaLista

	cmp qword rbx, NULL
	mov rdi, [rbx+offset_hijos]
	mov rsi, r14  
	mov rdx, r13
	call dame_prefijos

	mov rdi, [rbx+offset_sig]
	mov rsi, r15
	mov rdx, r13
	call dame_prefijos

	mov rdi, r14
	call free

	add rsp, 8
	pop r15
	pop r14
	pop r13
	pop r12
	pop rbx
	pop rbp
	ret

.agregarALaLista:

	mov rdi, r13
	mov rsi, r14
	call lista_agregar

	mov rdi, [rbx+offset_hijos]
        mov rsi, r14
        mov rdx, r13
        call dame_prefijos

        mov rdi, [rbx+offset_sig]
        mov rsi, r15
        mov rdx, r13
        call dame_prefijos

	mov rdi, r14
        call free

	add rsp, 8
	pop r15
        pop r14
        pop r13
        pop r12
        pop rbx
        pop rbp
	ret


.terminar:

	add rsp, 8
	pop r15
 	pop r14
        pop r13
        pop r12
        pop rbx
        pop rbp
        ret

;}



; const char *caracteres_en_tecla(char tecla){

caracteres_de_tecla:

	push rbp
        mov rbp, rsp
	push r12
	sub rsp, 8

	mov r12, rdi
	
	mov rdi, 6
	call malloc

	mov rcx, r12
	mov dil, cl
	
	cmp dil, 49
	je .aUno
	cmp dil, 50
	je .aDos
	cmp dil, 51
	je .aTres
	cmp dil, 52
	je .aCuatro
	cmp dil, 53
	je .aCinco
	cmp dil, 54
	je .aSeis
	cmp dil, 55
	je .aSiete
	cmp dil, 56
	je .aOcho
	cmp dil, 57
	
.aUno: 
	mov [rax], byte '1'
	mov [rax+1], byte NULL
	
	add rsp, 8
	pop r12
	pop rbp
	ret

.aDos:
	mov [rax], dword '2abc'
	mov [rax+4], byte NULL
	
	add rsp, 8
	pop r12
	pop rbp
        ret

.aTres: 	
	mov [rax], dword  '3def'
	mov [rax +4], byte NULL
	add rsp, 8
	pop r12
        pop rbp
        ret


.aCuatro:

	mov [rax], dword '4ghi' 
	mov [rax+4], byte NULL
	add rsp, 8
	pop r12
        pop rbp
        ret


.aCinco:
	mov [rax], dword '5jkl'
	mov [rax+4],byte  NULL
	add rsp, 8
	pop r12
        pop rbp
        ret



.aSeis:
	mov [rax], dword  '6nmo'
	mov [rax+4], byte  NULL
	add rsp, 8
	pop r12
        pop rbp
        ret


.aSiete:
	mov [rax], dword '7pqr'
	mov [rax+4], byte 's'
	mov [rax+5], byte NULL
	add rsp, 8
	pop r12
        pop rbp
        ret


.aOcho:
	mov [rax], dword '8tuv'
	mov[rax+4], byte NULL
	add rsp, 8
	pop r12
	pop rbp
        ret

.aNueve:
	mov [rax], dword '9wxy'
	mov [rax+4], byte 'z'
	mov [rax+5], byte NULL
	add rsp, 8
	pop r12
	pop rbp
        ret
;}


; FUNCIONES OBLIGATORIAS. PUEDEN CREAR LAS FUNCIONES AUXILIARES QUE CREAN CONVENIENTES

;trie *trie_crear(void){

trie_crear:

	; COMPLETAR AQUI EL CODIGO
	;armo stack frame
	;no modifico RBX, R12, R13, R14 y R15

	push rbp				;estoy alineado
	mov rbp, rsp

	xor rdi, rdi				;limpio el registro
	mov rdi, size_trie
	call malloc
	mov qword [rax+offset_raiz], NULL

	pop rbp
	ret

;}

;void trie_borrar(trie* t){

trie_borrar:

	; COMPLETAR AQUI EL CODIGO
	push rbp
        mov rbp, rsp
	push r12

	sub rsp, 8		;alineo la pila

	mov r12, rdi

	cmp qword [rdi+offset_raiz], NULL
	je .liberaTrie
	mov rdi, [rdi+offset_raiz] ; primero libera a sus hijos y despues se borra el trie
	call recorrerYBorrar

.liberaTrie:

	mov rdi, r12
	call free

	add rsp, 8
	pop r12
     	pop rbp
	ret

;}

nodo_crear:

	; COMPLETAR AQUI EL CODIGO
	;armo stack frame
	;no modifico R12, R13, R14 y R15

	push rbp
	mov rbp, rsp

	push rbx
	sub rsp,8			;alineo la pila

	xor rbx, rbx			;limpio rbx


	
	call convertir 

	mov bl, al
	mov rdi, size_nodo

	call malloc
	mov qword [rax+offset_sig], NULL
	mov qword [rax+offset_hijos], NULL
	mov [rax+offset_c], bl
	mov [rax+offset_fin], byte FALSE

	add rsp, 8
        pop rbx
        pop rbp
	ret

;nodo* insertar_nodo_en_nivel(nodo** nivel, char c){
insertar_nodo_en_nivel:

	; COMPLETAR AQUI EL CODIGO
	;stack frame
	;no modifico R12, R14, R15

	push rbp
        mov rbp, rsp
	push rbx
	push r13

	;rdi(nivel), sil(c)
	mov rbx, rdi
	mov r12, rsi
	mov r13, [rdi+offset_raiz]

.ciclo:
	cmp qword [rbx], NULL
	je .insertarPorNull
	cmp byte [r13+offset_c], sil
	je .esIgual
	jg .insertarPorOrden
	lea rbx, [r13+offset_sig]
	mov r13, [rbx]
	jmp .ciclo

.esIgual:

	mov rax, [rbx]
	pop r13
	pop rbx
	pop rbp
	ret

.insertarPorNull:

	mov dil, sil
	call nodo_crear
	mov [rbx] , rax

	pop r13
	pop rbx
	pop rbp
	ret

.insertarPorOrden:

	mov dil, sil
	call nodo_crear
	mov [rax+offset_sig], r13
	mov [rbx], rax

	pop r13
	pop rbx
	pop rbp
	ret

;}

;void trie_agregar_palabra(trie* t, char*p){

trie_agregar_palabra:
	; COMPLETAR AQUI EL CODIGO

	;stack frame

	push rbp
        mov rbp, rsp
        push rbx
	push r12
	push r13
	sub rsp, 8

	mov rbx, rdi		;direccion de memoria del puntero al nodo
	mov r13, rsi		;apunto r13 a la palabra

	cmp sil, NULL
	je .noAgregoNada
.ciclo:

	cmp [r13], byte NULL
	je .termino

	mov rdi, rbx
	mov sil, byte [r13]

	call insertar_nodo_en_nivel
	lea rbx, [rax+offset_hijos]

	add r13, 1

	jmp .ciclo

.termino:

	mov byte [rax+offset_fin], TRUE   ;se agregó una palabra

.noAgregoNada:

	add rsp, 8
	pop r13
	pop r12
	pop rbx
	pop rbp
	ret
;}

;trie *trie_construir(char* nombre_archivo){

trie_construir:

	;COMPLETAR AQUI EL CODIGO
	;stack frame

        push rbp
        mov rbp, rsp
        push rbx
        push r12
        push r13
	push r14
	push r15
	sub rsp, 8		;alineo la pila

	mov r12, rdi
	
	xor rdi, rdi

	mov rdi, 1024
	call malloc		; creo un buffer para guardar las palabras que voy le leyendo del archivo, que ire guardando en el trie
	mov r15, rax		; apunto al buffer desde r15

	mov rdi, r12
	mov rsi, file_mode	; archivo solo lectura
	call fopen
	mov r12, rax

	cmp r12, NULL
	je .noPuedoAbrirArchivo     ;si no pudo abrir el archivo la función se retorna 

	call trie_crear
	mov r14, rax		    ;apunto al trie recien creado

	xor r13, r13

.ciclo:

	cmp r13d, 0xFFFFFFFF
	je .llegueAlFinal

	mov rdi, r12                    ;parámetros de fscanf
        mov rsi, scan_mode
        mov rdx, r15
        call fscanf
	mov r13, rax

	mov rdi, r14
        mov rsi, r15                    ;intruduzco en el trie la palabra leida
        call trie_agregar_palabra

	jmp .ciclo

.llegueAlFinal:

	mov rdi, r15
	call free

	mov rdi, r12
	call fclose

	mov rax, r14

	add rsp, 8

	pop r15
	pop r14
        pop r13
        pop r12
        pop rbx
        pop rbp
        ret

.noPuedoAbrirArchivo:

	mov rdi, r15
        call free

	mov qword rax, NULL ; si no puedo abrir el archivo devuelvo un puntero NULL

	add rsp, 8

        pop r15
        pop r14
        pop r13
        pop r12
        pop rbx
        pop rbp
        ret



;}

;void imprimir_trie(trie *t, char* str){

trie_imprimir:

	; COMPLETAR AQUI EL CODIGO
	;stack frame
        push rbp
        mov rbp, rsp 

	%define var [rbp-8]	
	mov var, byte NULL ;inicializo la variable

	sub rsp, 8 ; dejos espacio en la pila para var

        push rbx
        push r12
	push r13
	   
	mov r12, rdi

	mov rdi, rsi
	mov rsi, append_mode
	call fopen
	mov rbx, rax

	mov rdi, r12
	lea r8, [rbp-8]
	mov rsi, r8  	
	call palabras_con_prefijo
	mov r12, [rax+offset_prim] 
	mov r13, rax

.palabrasDeLaLista:

	cmp r12, NULL
	je .terminoLaLista	
	mov r8, [r12+offset_valor] 			;apunto al string 

	;parametros para fprintf rdi(*fichero), rsi(formato) 
	mov rdi, rbx
	mov rsi, scan_mode
	mov rdx, r8
 	call fprintf
	mov r12, [r12+offset_sig_lnodo]
	jmp .palabrasDeLaLista	

.terminoLaLista:	
	 
	xor rsi, rsi
	mov rdi, rbx
	mov rsi, salto
	call fprintf
 
	mov rdi, rbx
	call fclose

	mov rdi, r13
	call lista_borrar

	pop r13
	pop r12
	pop rbx
	add rsp, 8
	pop rbp
	ret

;}

;bool buscar_palabra(trie* t, char* p){
buscar_palabra:

	; COMPLETAR AQUI EL CODIGO
	;stack frame
      
 	push rbp
        mov rbp, rsp
        push rbx
        push r12

	mov rbx, [rdi]
	mov r12, rsi

.ciclo:

	cmp [r12], byte NULL
	je .termino
	mov rdi, rbx
	mov sil, byte [r12]
	call nodo_buscar
	cmp qword rax, NULL
	je .noEsta
	mov rbx, [rax+offset_hijos]
	add r12, 1
	jmp .ciclo

.noEsta:

	mov qword rax, FALSE
	pop r12
	pop rbx
	pop rbp
	ret

.termino:

	cmp byte [rax+offset_fin], FALSE
	je .false


	mov qword rax, TRUE
        pop r12
        pop rbx
        pop rbp
        ret

.false:

	mov qword rax, FALSE
	pop r12
	pop rbx
	pop rbp
	ret

;}

trie_pesar:
	; COMPLETAR AQUI EL CODIGO

	;stack frame
	push rbp
	mov rbp, rsp
	push rbx
	push r12
	push r13
	push r14
	push r15
	sub r15, 8

	mov rbx, rdi  ;direccion de memoria del trie
	mov r12, rsi  ;direccion de memoria de la funcion

	xor r14, r14
	
	xor rdi, rdi
	mov rdi, 16
	call malloc 
	mov r15, rax	
	
	xor rdi, rdi

	mov dil, 1
	call malloc
	mov [rax], byte NULL
	
	mov rdi, rbx
	mov rsi, rax
	call palabras_con_prefijo

	mov r13, [rax+offset_prim]
	
.ciclo:
	cmp r13, qword NULL
	je .termino
	mov rdi, [r13+offset_valor] 
	call r12
	xor rcx, rcx
	movups [r15], xmm0	
	add  r14, rcx
	mov r13, [r13+offset_sig_lnodo]
	jmp .ciclo

.termino:
 
	

	 pxor xmm0, xmm0	
	 movups xmm0, xmm0


	 pop r14
	 pop r13
	 pop r12
	 pop rbx
	 pop rbp
	 ret 	



palabras_con_prefijo:

	;COMPLETAR AQUI EL CODIGO
	;stack frame
        
	push rbp
        mov rbp, rsp
        push rbx
        push r12
	push r13
	push r14
	push r15
	sub rsp, 8

	mov r15, rdi

	mov rbx, [rdi+offset_raiz]
	mov r12, rsi

	mov rdi, rbx

	call nodo_prefijo
	mov r13, rax

	call lista_crear
	mov r14, rax

	mov rdi, r15
	mov rsi, r12		
	call buscar_palabra
	cmp al, 1
	je .elPrefijoEsta

	mov rdi, r13
        mov rsi, r12
        mov rdx, r14

        call dame_prefijos

        mov rax, r14

        add rsp, 8
        pop r15
        pop r14
        pop r13
        pop r12
        pop rbx
        pop rbp
        ret

.elPrefijoEsta:

	mov rdi, r14
	mov rsi, r12
	call lista_agregar

	mov rdi, r13
	mov rsi, r12
	mov rdx, r14

	call dame_prefijos

	mov rax, r14

	add rsp, 8
	pop r15
	pop r14
	pop r13
	pop r12
	pop rbx
	pop rbp
	ret
